#ifndef UDKOS_H
#define UDKOS_H

#include "platform.h"
#include "event.h"
#include <string>
/*
 * OS denpendent
*/
#if defined(ANDROID) 
#define HAVE_GETTID 1
#define HAVE_ANDROID_OS 1
#define HAVE_PTHREADS 1
//#define HAVE_POSIX_CLOCKS 1
#include <pthread.h>
#elif defined(__linux)||defined(__APPLE__)
#define HAVE_PTHREADS 1
//#define HAVE_POSIX_CLOCKS 1
#include <pthread.h>
#endif

typedef UDK_S32   status_t;

typedef long long nsecs_t;
#ifndef NO_ERROR
#define NO_ERROR 0
#endif
#ifndef UNKNOWN_ERROR
#define UNKNOWN_ERROR 0x80000000
#endif

enum {
    /*
     * ***********************************************
     * ** Keep in sync with android.os.Process.java **
     * ***********************************************
     * 
     * This maps directly to the "nice" priorites we use in Android.
     * A thread priority should be chosen inverse-proportinally to
     * the amount of work the thread is expected to do. The more work
     * a thread will do, the less favorable priority it should get so that 
     * it doesn't starve the system. Threads not behaving properly might
     * be "punished" by the kernel.
     * Use the levels below when appropriate. Intermediate values are
     * acceptable, preferably use the {MORE|LESS}_FAVORABLE constants below.
     */
    PRIORITY_LOWEST         =  19,

    /* use for background tasks */
    PRIORITY_BACKGROUND     =  10,
    
    /* most threads run at normal priority */
    PRIORITY_NORMAL         =   0,
    
    /* threads currently running a UI that the user is interacting with */
    PRIORITY_FOREGROUND     =  -2,

    /* the main UI thread has a slightly more favorable priority */
    PRIORITY_DISPLAY        =  -4,
    
    /* ui service treads might want to run at a urgent display (uncommon) */
    PRIORITY_URGENT_DISPLAY =  -8,
    
    /* all normal audio threads */
    PRIORITY_AUDIO          = -16,
    
    /* service audio threads (uncommon) */
    PRIORITY_URGENT_AUDIO   = -19,

    /* should never be used in practice. regular process might not 
     * be allowed to use this level */
    PRIORITY_HIGHEST        = -20,

    PRIORITY_DEFAULT        = PRIORITY_NORMAL,
    PRIORITY_MORE_FAVORABLE = -1,
    PRIORITY_LESS_FAVORABLE = +1,
};

enum {
    TGROUP_DEFAULT          = 0,
    TGROUP_BG_NONINTERACT   = 1,
    TGROUP_FG_BOOST         = 2,
    TGROUP_MAX              = TGROUP_FG_BOOST,
};

typedef void* thread_id_t;

typedef int (*thread_func_t)(void*);

#ifdef __cplusplus
extern "C" {
#endif
// Create and run a new thread.
extern int udkCreateThread(thread_func_t, void *);

// Create thread with lots of parameters
extern int udkCreateThreadEtc(thread_func_t entryFunction,
                                  void *userData,
                                  const char* threadName,
                                  UDK_S32 threadPriority,
                                  size_t threadStackSize,
                                  thread_id_t *threadId);

// Get some sort of unique identifier for the current thread.
extern thread_id_t udkGetThreadId();

// Low-level thread creation -- never creates threads that can
// interact with the Java VM.
extern int udkCreateRawThreadEtc(thread_func_t entryFunction,
                                     void *userData,
                                     const char* threadName,
                                     UDK_S32 threadPriority,
                                     size_t threadStackSize,
                                     thread_id_t *threadId);

// Used by the Java Runtime to control how threads are created, so that
// they can be proper and lovely Java threads.
typedef int (*create_thread_fn)(thread_func_t entryFunction,
                                        void *userData,
                                        const char* threadName,
                                        UDK_S32 threadPriority,
                                        size_t threadStackSize,
                                        thread_id_t *threadId);

extern void SetCreateThreadFunc(create_thread_fn func);

// Get pid for the current thread.
extern pid_t udkGetTid();

#ifdef __cplusplus
}
#endif

// Create and run a new thread.
inline bool createThread(thread_func_t f, void *a) {
    return udkCreateThread(f, a) ? true : false;
}

// Create thread with lots of parameters
inline bool createThreadEtc(thread_func_t entryFunction,
                            void *userData,
                            const char* threadName = "udk:unnamed_thread",
                            int32_t threadPriority = PRIORITY_DEFAULT,
                            size_t threadStackSize = 0,
                            thread_id_t *threadId = 0)
{
    return udkCreateThreadEtc(entryFunction, userData, threadName,
        threadPriority, threadStackSize, threadId) ? true : false;
}

// Get some sort of unique identifier for the current thread.
inline thread_id_t getThreadId() {
    return udkGetThreadId();
}

/*
 * Simple mutex class.  The implementation is system-dependent.
 *
 * The mutex must be unlocked by the thread that locked it.  They are not
 * recursive, i.e. the same thread can't lock it multiple times.
 */
class Mutex {
public:
    enum {
        PRIVATE = 0,
        SHARED = 1
    };
    
                Mutex();
                Mutex(const char* name);
                Mutex(int type, const char* name = NULL);
                ~Mutex();

    // lock or unlock the mutex
    status_t    lock();
    void        unlock();

    // lock if possible; returns 0 on success, error otherwise
    status_t    tryLock();

    // Manages the mutex automatically. It'll be locked when Autolock is
    // constructed and released when Autolock goes out of scope.
    class Autolock {
    public:
        inline Autolock(Mutex& mutex) : mLock(mutex)  { mLock.lock(); }
        inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
        inline ~Autolock() { mLock.unlock(); }
    private:
        Mutex& mLock;
    };

private:
    friend class Condition;
    
    // A mutex cannot be copied
                Mutex(const Mutex&);
    Mutex&      operator = (const Mutex&);
    
#if defined(HAVE_PTHREADS)
		pthread_mutex_t mMutex;
#else
		void	_init();
		void*	mState;
#endif
};


/*
 * Automatic mutex.  Declare one of these at the top of a function.
 * When the function returns, it will go out of scope, and release the
 * mutex.
 */
 
typedef Mutex::Autolock AutoMutex;

/*
 * Condition variable class.  The implementation is system-dependent.
 *
 * Condition variables are paired up with mutexes.  Lock the mutex,
 * call wait(), then either re-wait() if things aren't quite what you want,
 * or unlock the mutex and continue.  All threads calling wait() must
 * use the same mutex for a given Condition.
 */
class Condition {
public:
    enum {
        PRIVATE = 0,
        SHARED = 1
    };

    Condition();
    Condition(int type);
    ~Condition();
    // Wait on the condition variable.  Lock the mutex before calling.
    status_t wait(Mutex& mutex);
    // same with relative timeout
    status_t waitRelative(Mutex& mutex, nsecs_t reltime);

	
    // Wait on the condition variable.  Lock the mutex before calling.
    status_t wait(Mutex* mutex);
    // same with relative timeout
    status_t waitRelative(Mutex* mutex, nsecs_t reltime);

    // Signal the condition variable, allowing one thread to continue.
    void signal();
    // Signal the condition variable, allowing all threads to continue.
    void broadcast();

private:
#if defined(HAVE_PTHREADS)
		pthread_cond_t mCond;
#else
		void*	mState;
#endif
};



/*
 * This is our spiffy thread object!
 */

class Thread 
{
public:
    // Create a Thread object, but doesn't create or start the associated
    // thread. See the run() method.
                        Thread(bool canCallJava = true);
    virtual             ~Thread();

    // Start the thread in threadLoop() which needs to be implemented.
    virtual status_t    run(    const char* name = 0,
                                UDK_S32 priority = PRIORITY_DEFAULT,
                                size_t stack = 0);
    
    // Ask this object's thread to exit. This function is asynchronous, when the
    // function returns the thread might still be running. Of course, this
    // function can be called from a different thread.
    virtual void        requestExit();

    // Good place to do one-time initializations
    virtual status_t    readyToRun();
       
    // Call requestExit() and wait until this object's thread exits.
    // BE VERY CAREFUL of deadlocks. In particular, it would be silly to call
    // this function from this object's thread. Will return WOULD_BLOCK in
    // that case.
            status_t    requestExitAndWait();

protected:
    // exitPending() returns true if requestExit() has been called.
            bool        exitPending() const;
    
private:
    // Derived class must implement threadLoop(). The thread starts its life
    // here. There are two ways of using the Thread object:
    // 1) loop: if threadLoop() returns true, it will be called again if
    //          requestExit() wasn't called.
    // 2) once: if threadLoop() returns false, the thread will exit upon return.
    virtual bool        threadLoop() = 0;

private:
    Thread& operator=(const Thread&);
    static  int             _threadLoop(void* user);
    const   bool            mCanCallJava;
            thread_id_t     mThread;
            Mutex           mLock;
            Condition       mThreadExitedCondition;
            status_t        mStatus;
    volatile bool           mExitPending;
    volatile bool           mRunning;
     int             mTid;
};


#define MILLISECONDS_CONVERSION 1000
#define MICROSECONDS_CONVERSION 1000000

/// Class to abstract socket communications in a cross platform manner.
/// This class is designed 
class CStatTimer {
public:
    CStatTimer();
    ~CStatTimer();
    void Initialize();

    struct timeval GetStartTime();
    void SetStartTime();

    struct timeval GetEndTime();
    void SetEndTime();

    UDK_U32 GetMilliSeconds();
    UDK_U32 GetMicroSeconds();
    UDK_U32 GetSeconds();

    UDK_U32 GetCurrentTime();

private:
    UDK_U32 CalcTotalUSec();

private:
    struct timeval  m_startTime;
    struct timeval  m_endTime;
};


#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <netinet/ip.h>
#include <netdb.h>

typedef int SOCKET;
/// Provides a platform independent class to for socket development.
/// This class is designed to abstract socket communication development in a 
/// platform independent manner. 
/// - Socket types
///  -# CActiveSocket Class
///  -# CPassiveSocket Class
class CSimpleSocket {
public:
    /// Defines the three possible states for shuting down a socket.
    typedef enum 
    {
        Receives = SHUT_RD, ///< Shutdown passive socket.
        Sends = SHUT_WR,    ///< Shutdown active socket.
        Both = SHUT_RDWR    ///< Shutdown both active and passive sockets.
    } CShutdownMode; 

    /// Defines the socket types defined by CSimpleSocket class.
    typedef enum  
    {
        SocketTypeInvalid,   ///< Invalid socket type.
        SocketTypeTcp,       ///< Defines socket as TCP socket.
        SocketTypeUdp,       ///< Defines socket as UDP socket.
        SocketTypeTcp6,      ///< Defines socket as IPv6 TCP socket.
        SocketTypeUdp6,      ///< Defines socket as IPv6 UDP socket.
        SocketTypeRaw        ///< Provides raw network protocol access.
    } CSocketType;

    /// Defines all error codes handled by the CSimpleSocket class.
    typedef enum 
    {
        SocketError = -1,          ///< Generic socket error translates to error below.
        SocketSuccess = 0,         ///< No socket error.
        SocketInvalidSocket,       ///< Invalid socket handle.
        SocketInvalidAddress,      ///< Invalid destination address specified.
        SocketInvalidPort,         ///< Invalid destination port specified.
        SocketConnectionRefused,   ///< No server is listening at remote address.
        SocketTimedout,            ///< Timed out while attempting operation.
        SocketEwouldblock,         ///< Operation would block if socket were blocking.
        SocketNotconnected,        ///< Currently not connected.
        SocketEinprogress,         ///< Socket is non-blocking and the connection cannot be completed immediately
        SocketInterrupted,         ///< Call was interrupted by a signal that was caught before a valid connection arrived.
        SocketConnectionAborted,   ///< The connection has been aborted.
        SocketProtocolError,       ///< Invalid protocol for operation.
        SocketFirewallError,       ///< Firewall rules forbid connection.
        SocketInvalidSocketBuffer, ///< The receive buffer point outside the process's address space.
        SocketConnectionReset,     ///< Connection was forcibly closed by the remote host.
        SocketAddressInUse,        ///< Address already in use.
        SocketInvalidPointer,      ///< Pointer type supplied as argument is invalid.
        SocketEunknown             ///< Unknown error please report to mark@carrierlabs.com
    } CSocketError;

public:
    CSimpleSocket(CSocketType type = SocketTypeTcp);
	CSimpleSocket(CSimpleSocket &socket);

    virtual ~CSimpleSocket() 
	{
		if (m_pBuffer != NULL)
		{
			delete [] m_pBuffer;
			m_pBuffer = NULL;
		}
	};

    /// Initialize instance of CSocket.  This method MUST be called before an
    /// object can be used. Errors : CSocket::SocketProtocolError, 
    /// CSocket::SocketInvalidSocket,
    /// @return true if properly initialized.
    virtual bool Initialize(void);

	/// Close socket
	/// @return true if successfully closed otherwise returns false.
	virtual bool Close(void);

	/// Shutdown shut down socket send and receive operations
	///	CShutdownMode::Receives - Disables further receive operations.
	///	CShutdownMode::Sends    - Disables further send operations.
	///	CShutdownBoth::         - Disables further send and receive operations.
	/// @param nShutdown specifies the type of shutdown. 
	/// @return true if successfully shutdown otherwise returns false.
	virtual bool Shutdown(CShutdownMode nShutdown);

    /// Examine the socket descriptor sets currently owned by the instance of
    /// the socket class (the readfds, writefds, and errorfds parameters) to 
    /// see whether some of their descriptors are ready for reading, are ready 
    /// for writing, or have an exceptional condition pending, respectively.
	/// Block until an event happens on the specified file descriptors.
    /// @return true if socket has data ready, or false if not ready or timed out.
    virtual bool Select(void) { return Select(0,0); };

    /// Examine the socket descriptor sets currently owned by the instance of
    /// the socket class (the readfds, writefds, and errorfds parameters) to 
    /// see whether some of their descriptors are ready for reading, are ready 
    /// for writing, or have an exceptional condition pending, respectively.
	/// @param nTimeoutSec timeout in seconds for select.
    /// @param nTimeoutUSec timeout in micro seconds for select.
    /// @return true if socket has data ready, or false if not ready or timed out.
    virtual bool Select(UDK_S32 nTimeoutSec, UDK_S32 nTimeoutUSec);

	/*
	* 0->select read,write,error,
	* 1->select read
	* 2->select write
	* 4->select error
	*/
    virtual bool Select(UDK_S32 nTimeoutSec, UDK_S32 nTimeoutUSec,int option);

    /// Does the current instance of the socket object contain a valid socket
    /// descriptor.
    ///  @return true if the socket object contains a valid socket descriptor.
    virtual bool IsSocketValid(void) { return (m_socket != SocketError); };

    /// Provides a standard error code for cross platform development by
    /// mapping the operating system error to an error defined by the CSocket
    /// class.
    void TranslateSocketError(void);

    /// Attempts to receive a block of data on an established connection.	
    /// @param nMaxBytes maximum number of bytes to receive.
    /// @return number of bytes actually received.
	/// @return of zero means the connection has been shutdown on the other side.
	/// @return of -1 means that an error has occurred.
    virtual UDK_S32 Receive(UDK_S32 nMaxBytes = 1);

    /// Attempts to send a block of data on an established connection.
    /// @param pBuf block of data to be sent.
    /// @param bytesToSend size of data block to be sent.
    /// @return number of bytes actually sent.
	/// @return of zero means the connection has been shutdown on the other side.
	/// @return of -1 means that an error has occurred.
    virtual UDK_S32 Send(const UDK_U8 *pBuf, size_t bytesToSend);

    /// Attempts to send at most nNumItem blocks described by sendVector 
    /// to the socket descriptor associated with the socket object.
    /// @param sendVector pointer to an array of iovec structures
    /// @param nNumItems number of items in the vector to process
    /// <br>\b NOTE: Buffers are processed in the order specified.
    /// @return number of bytes actually sent, return of zero means the
    /// connection has been shutdown on the other side, and a return of -1
    /// means that an error has occurred.
    virtual UDK_S32 Send(const struct iovec *sendVector, UDK_S32 nNumItems);

    /// Copies data between one file descriptor and another.  
    /// On some systems this copying is done within the kernel, and thus is 
    /// more efficient than the combination of CSimpleSocket::Send and 
    /// CSimpleSocket::Receive, which would require transferring data to and 
    /// from user space.  
    /// <br>\b Note: This is available on all implementations, but the kernel 
    /// implementation is only available on Unix type systems.
	/// @param nOutFd descriptor opened for writing.
    /// @param nInFd descriptor opened for reading.
    /// @param pOffset from which to start reading data from input file.
    /// @param nCount number of bytes to copy between file descriptors.
    /// @return number of bytes written to the out socket descriptor.
    virtual UDK_S32 SendFile(UDK_S32 nOutFd, UDK_S32 nInFd, off_t *pOffset, UDK_S32 nCount);

    /// Returns blocking/non-blocking state of socket.
    /// @return true if the socket is non-blocking, else return false.
    bool IsNonblocking(void) { return (m_bIsBlocking == false); };

    /// Set the socket to blocking.
    /// @return true if successful set to blocking, else return false;
    bool SetBlocking(void);

    /// Set the socket as non-blocking.
    /// @return true if successful set to non-blocking, else return false;
    bool SetNonblocking(void);

    /// Get a pointer to internal receive buffer.  The user MUST not free this
    /// pointer when finished.  This memory is managed internally by the CSocket 
    /// class.
    /// @return pointer to data if valid, else returns NULL.
    UDK_U8 *GetData(void)  { return m_pBuffer; };

    /// Returns the number of bytes received on the last call to 
    /// CSocket::Receive().
    /// @return number of bytes received.
    UDK_S32 GetBytesReceived(void) { return m_nBytesReceived; };

    /// Returns the number of bytes sent on the last call to 
    /// CSocket::Send().
    /// @return number of bytes sent.
    UDK_S32 GetBytesSent(void) { return m_nBytesSent; };

    /// Controls the actions taken when CSimpleSocket::Close is executed on a 
    /// socket object that has unsent data.  The default value for this option 
    /// is \b off.
    /// - Following are the three possible scenarios.
    ///  -# \b bEnable is false, CSimpleSocket::Close returns immediately, but 
    ///  any unset data is transmitted (after CSimpleSocket::Close returns)
    ///  -# \b bEnable is true and \b nTime is zero, CSimpleSocket::Close return 
    /// immediately and any unsent data is discarded.
    ///  -# \b bEnable is true and \b nTime is nonzero, CSimpleSocket::Close does
    ///  not return until all unsent data is transmitted (or the connection is 
    ///  Closed by the remote system).
    /// <br><p>
    /// @param bEnable true to enable option false to disable option.
    /// @param nTime time in seconds to linger.
    /// @return true if option successfully set
    bool SetOptionLinger(bool bEnable, UDK_U16 nTime);

    /// Tells the kernel that even if this port is busy (in the TIME_WAIT state),
    /// go ahead and reuse it anyway.  If it is busy, but with another state, 
    /// you will still get an address already in use error.
    /// @return true if option successfully set
    bool SetOptionReuseAddr();

    /// Gets the timeout value that specifies the maximum number of seconds a
    /// call to CSimpleSocket::Open waits until it completes. 
    /// @return the length of time in seconds
    UDK_S32 GetConnectTimeoutSec(void) { return  m_stConnectTimeout.tv_sec; };

    /// Gets the timeout value that specifies the maximum number of microseconds
    /// a call to CSimpleSocket::Open waits until it completes. 
    /// @return the length of time in microseconds
    UDK_S32 GetConnectTimeoutUSec(void) { return  m_stConnectTimeout.tv_usec; };

    /// Sets the timeout value that specifies the maximum amount of time a call 
    /// to CSimpleSocket::Receive waits until it completes. Use the method
    /// CSimpleSocket::SetReceiveTimeout to specify the number of seconds to wait.
    /// If a call to CSimpleSocket::Receive has blocked for the specified length of
    /// time without receiving additional data, it returns with a partial count 
    /// or CSimpleSocket::GetSocketError set to CSimpleSocket::SocketEwouldblock if no data 
    /// were received. 
    /// @param nConnectTimeoutSec of timeout in seconds.
    /// @param nConnectTimeoutUsec of timeout in microseconds.
    /// @return true if socket connection timeout was successfully set.
    void SetConnectTimeout(UDK_S32 nConnectTimeoutSec, UDK_S32 nConnectTimeoutUsec = 0) 
    { 
        m_stConnectTimeout.tv_sec = nConnectTimeoutSec; 
        m_stConnectTimeout.tv_usec = nConnectTimeoutUsec; 
    };

    /// Gets the timeout value that specifies the maximum number of seconds a
    /// a call to CSimpleSocket::Receive waits until it completes. 
    /// @return the length of time in seconds
    UDK_S32 GetReceiveTimeoutSec(void) { return  m_stRecvTimeout.tv_sec; };

    /// Gets the timeout value that specifies the maximum number of microseconds
    /// a call to CSimpleSocket::Receive waits until it completes. 
    /// @return the length of time in microseconds
    UDK_S32 GetReceiveTimeoutUSec(void) { return  m_stRecvTimeout.tv_usec; };

    /// Sets the timeout value that specifies the maximum amount of time a call 
    /// to CSimpleSocket::Receive waits until it completes. Use the method
    /// CSimpleSocket::SetReceiveTimeout to specify the number of seconds to wait.
    /// If a call to CSimpleSocket::Receive has blocked for the specified length of
    /// time without receiving additional data, it returns with a partial count 
    /// or CSimpleSocket::GetSocketError set to CSimpleSocket::SocketEwouldblock if no data 
    /// were received. 
    ///  @param nRecvTimeoutSec of timeout in seconds.
    ///  @param nRecvTimeoutUsec of timeout in microseconds.
    ///  @return true if socket timeout was successfully set.
    bool SetReceiveTimeout(UDK_S32 nRecvTimeoutSec, UDK_S32 nRecvTimeoutUsec = 0);

    /// Enable/disable multicast for a socket.  This options is only valid for
    /// socket descriptors of type CSimpleSocket::SocketTypeUdp.
    /// @return true if multicast was enabled or false if socket type is not
    /// CSimpleSocket::SocketTypeUdp and the error will be set to 
    /// CSimpleSocket::SocketProtocolError 
    bool SetMulticast(bool bEnable, UDK_U8 multicastTTL = 1);

    /// Return true if socket is multicast or false is socket is unicast
    /// @return true if multicast is enabled
    bool GetMulticast() { return m_bIsMulticast; };

    /// Enable/disable broadcast for a socket.  This options is only valid for
    /// socket descriptors of type CSimpleSocket::SocketTypeUdp.
    /// @return true if broadcast was enabled or false if socket type is not
    /// CSimpleSocket::SocketTypeUdp and the error will be set to 
    /// CSimpleSocket::SocketProtocolError 
    bool SetBroadcast(bool bEnable);

    bool IsBroadcadstAddr(UDK_U32 u32IP) const 
    {
    	UDK_U32 subnet =  u32IP&0xFFFFFFFF;
    	if(((subnet&0xff)==0xff)||
    		((subnet&0xff00)==0xff00)||
    		((subnet&0xff0000)==0xff0000)||
    		((subnet&0xff000000)==0xff000000))
    		return true;
    	return false;
    }
    bool IsMulticastAddr(UDK_U32 u32IP) const { return (((u32IP) & 0xf0000000) == 0xe0000000); }
    bool isMulticastAddress(const std::string &s)
    {
    	bool b = false;
    	try
    	{
    	    int i = atoi(s.substr(0, s.find(".")).c_str());
    	    if (i >= 224 && i <= 239)
    	        b = true;
    	}
    	catch (int i)
    	{
    	    b = false;
    	}
    	return b;
	}

    bool isBroadcastAddress(const std::string &s)
	{
    		bool b = false;
    		try
    		{
    		    if (s.rfind("255") != std::string::npos)
    		        b = true;
   		}
		    catch (int i)
    		{
        		b = false;
    		}
		return b;
	}

    /// Return true if socket is broadcast or false is socket is unicast
    /// @return true if broadcast is enabled
    bool GetBroadcast() { return m_bIsBroadcast; };

    /// Bind socket to a specific interface when using multicast.
    /// @return true if successfully bound to interface
    bool BindInterface(UDK_U8 *pInterface);

    /// Gets the timeout value that specifies the maximum number of seconds a
    /// a call to CSimpleSocket::Send waits until it completes. 
    /// @return the length of time in seconds
    UDK_S32 GetSendTimeoutSec(void) { return  m_stSendTimeout.tv_sec; };

    /// Gets the timeout value that specifies the maximum number of microseconds
    /// a call to CSimpleSocket::Send waits until it completes. 
    /// @return the length of time in microseconds
    UDK_S32 GetSendTimeoutUSec(void) { return  m_stSendTimeout.tv_usec; };

    /// Gets the timeout value that specifies the maximum amount of time a call 
    /// to CSimpleSocket::Send waits until it completes. 
    /// @return the length of time in seconds
    bool SetSendTimeout(UDK_S32 nSendTimeoutSec, UDK_S32 nSendTimeoutUsec = 0);

    /// Returns the last error that occured for the instace of the CSimpleSocket
    /// instance.  This method should be called immediately to retrieve the 
    /// error code for the failing mehtod call.
    ///  @return last error that occured.
    CSocketError GetSocketError(void) { return m_socketErrno; };

    /// Get the total time the of the last operation in milliseconds.
    ///  @return number of milliseconds of last operation.
    UDK_U32 GetTotalTimeMs() { return m_timer.GetMilliSeconds(); };

    /// Get the total time the of the last operation in microseconds.
    ///  @return number of microseconds or last operation.
    UDK_U32 GetTotalTimeUsec() { return m_timer.GetMicroSeconds(); };

    /// Return Differentiated Services Code Point (DSCP) value currently set on the socket object.
    /// @return DSCP for current socket object.
    /// <br><br> \b NOTE: Windows special notes http://support.microsoft.com/kb/248611.
	int GetSocketDscp(void);

	/// Set Differentiated Services Code Point (DSCP) for socket object.
	///  @param nDscp value of TOS setting which will be converted to DSCP
	///  @return true if DSCP value was properly set
    /// <br><br> \b NOTE: Windows special notes http://support.microsoft.com/kb/248611.
	bool SetSocketDscp(int nDscp);

	/// Return socket descriptor
	///  @return socket descriptor which is a signed 32 bit integer.
    SOCKET GetSocketDescriptor() { return m_socket; };

	/// Return socket descriptor
	///  @return socket descriptor which is a signed 32 bit integer.
    CSocketType GetSocketType() { return m_nSocketType; };

    /// Returns clients Internet host address as a string in standard numbers-and-dots notation.
	///  @return NULL if invalid
    UDK_U8 *GetClientAddr() { return (UDK_U8 *)inet_ntoa(m_stClientSockaddr.sin_addr); };

	/// Returns the port number on which the client is connected.
	///  @return client port number.
    UDK_S16 GetClientPort() { return m_stClientSockaddr.sin_port; };

    /// Returns server Internet host address as a string in standard numbers-and-dots notation.
	///  @return NULL if invalid
    UDK_U8 *GetServerAddr() { return (UDK_U8 *)inet_ntoa(m_stServerSockaddr.sin_addr); };

	/// Returns the port number on which the server is connected.
	///  @return server port number.
    UDK_S16 GetServerPort() { return ntohs(m_stServerSockaddr.sin_port); };

    /// Get the TCP receive buffer window size for the current socket object.
    /// <br><br>\b NOTE: Linux will set the receive buffer to twice the value passed.
    ///  @return zero on failure else the number of bytes of the TCP receive buffer window size if successful.
    UDK_U32 GetReceiveWindowSize() { return GetWindowSize(SO_RCVBUF); };

    /// Get the TCP send buffer window size for the current socket object.
    /// <br><br>\b NOTE: Linux will set the send buffer to twice the value passed.
    ///  @return zero on failure else the number of bytes of the TCP receive buffer window size if successful.
    UDK_U32 GetSendWindowSize() { return GetWindowSize(SO_SNDBUF); };

    /// Set the TCP receive buffer window size for the current socket object.
    /// <br><br>\b NOTE: Linux will set the receive buffer to twice the value passed.
    ///  @return zero on failure else the number of bytes of the TCP send buffer window size if successful.
    UDK_U32 SetReceiveWindowSize(UDK_U32 nWindowSize) { return SetWindowSize(SO_RCVBUF, nWindowSize); };

    /// Set the TCP send buffer window size for the current socket object.
    /// <br><br>\b NOTE: Linux will set the send buffer to twice the value passed.
    ///  @return zero on failure else the number of bytes of the TCP send buffer window size if successful.
    UDK_U32 SetSendWindowSize(UDK_U32 nWindowSize) { return SetWindowSize(SO_SNDBUF, nWindowSize); };

    /// Disable the Nagle algorithm (Set TCP_NODELAY to true)
    /// @return false if failed to set socket option otherwise return true;
    bool DisableNagleAlgoritm();

    /// Enable the Nagle algorithm (Set TCP_NODELAY to false)
    /// @return false if failed to set socket option otherwise return true;
    bool EnableNagleAlgoritm();


protected:
    /// Set internal socket error to that specified error
    ///  @param error type of error
    void SetSocketError(CSimpleSocket::CSocketError error) { m_socketErrno = error; };

    /// Set object socket handle to that specified as parameter 
    ///  @param socket value of socket descriptor
    void SetSocketHandle(SOCKET socket) { m_socket = socket; };

private:
    /// Generic function used to get the send/receive window size
    ///  @return zero on failure else the number of bytes of the TCP window size if successful.
    UDK_U32 GetWindowSize(UDK_U32 nOptionName);

    /// Generic function used to set the send/receive window size
    ///  @return zero on failure else the number of bytes of the TCP window size if successful.
    UDK_U32 SetWindowSize(UDK_U32 nOptionName, UDK_U32 nWindowSize);


    /// Attempts to send at most nNumItem blocks described by sendVector 
    /// to the socket descriptor associated with the socket object.
    /// @param sendVector pointer to an array of iovec structures
    /// @param nNumItems number of items in the vector to process
    /// <br>\b Note: This implementation is for systems that don't natively
    /// support this functionality.
    /// @return number of bytes actually sent, return of zero means the
    /// connection has been shutdown on the other side, and a return of -1
    /// means that an error has occurred.
    UDK_S32 Writev(const struct iovec *pVector, size_t nCount);

    /// Flush the socket descriptor owned by the object.
	/// @return true data was successfully sent, else return false;
    bool Flush();

	CSimpleSocket *operator=(CSimpleSocket &socket);

protected:
    SOCKET               m_socket;            /// socket handle
    CSocketError         m_socketErrno;       /// number of last error
    UDK_U8               *m_pBuffer;           /// internal send/receive buffer
    UDK_S32                m_nBufferSize;       /// size of internal send/receive buffer
    UDK_S32                m_nSocketDomain;     /// socket type PF_INET, PF_INET6
    CSocketType          m_nSocketType;       /// socket type - UDP, TCP or RAW
    UDK_S32                m_nBytesReceived;    /// number of bytes received
    UDK_S32                m_nBytesSent;        /// number of bytes sent
    UDK_U32               m_nFlags;            /// socket flags
    bool                 m_bIsBlocking;       /// is socket blocking
    bool                 m_bIsMulticast;      /// is the UDP socket multicast;
    bool		 m_bIsBroadcast;
    struct timeval       m_stConnectTimeout;  /// connection timeout
    struct timeval       m_stRecvTimeout;     /// receive timeout
    struct timeval       m_stSendTimeout;     /// send timeout
    struct sockaddr_in   m_stServerSockaddr;  /// server address
    struct sockaddr_in   m_stClientSockaddr;  /// client address
    struct sockaddr_in   m_stMulticastGroup;  /// multicast group to bind to
    struct linger        m_stLinger;          /// linger flag
    CStatTimer           m_timer;             /// internal statistics.
    fd_set               m_writeFds;		  /// write file descriptor set
    fd_set               m_readFds;		      /// read file descriptor set
    fd_set               m_errorFds;		  /// error file descriptor set
};

#endif

